package com.common.base.widget.image_watcher

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.TypeEvaluator
import android.animation.ValueAnimator
import android.animation.ValueAnimator.AnimatorUpdateListener
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Message
import android.util.AttributeSet
import android.util.SparseArray
import android.util.TypedValue
import android.view.*
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import com.common.base.R
import com.common.base.utils.NavigationUtil.getDpi
import com.common.base.utils.NavigationUtil.getNavigationBarHeightIfRoom
import java.lang.ref.WeakReference

class ImageWatcher @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet?,
    btmViewProvider: BtmViewProvider? = null,
    activity: Activity? = null,
    fragment: Fragment? = null,
    isLoadingUIProvider: Boolean = true
) : FrameLayout(
    context!!, attrs
), GestureDetector.OnGestureListener, ViewPager.OnPageChangeListener {
    private val mHandler: Handler
    protected val MIN_SCALE = 0.5f // 显示中的图片最小缩小系数
    protected val MAX_SCALE = 3.6f // 显示中的图片最大放大系数
    protected var scaleSensitivity = 0.3f // 缩放灵敏度 越小越灵敏
    protected var edgeResilience = 0.16f // 边缘阻尼弹性 越小越难拉动
    private var iSource: ImageView? = null
    protected var mPlaceholderRes = R.mipmap.icon_img_default
    protected var mErrorImageRes = R.mipmap.icon_img_default_error // 图片加载失败站位图
    protected var mStatusBarHeight // 状态栏高度
            = 0
    private var mWidth = 0
    private var mHeight = 0
    private var mBackgroundColor = 0x00000000
    private var mTouchMode = TOUCH_MODE_NONE
    private var mTouchSlop = 0f
    private var mFingersDistance = 0f
    private var mFingersCenterX = 0f
    private var mFingersCenterY = 0f
    private var mExitRef // 触摸退出进度
            = 0f
    private var animFling: ValueAnimator? = null
    private var animBackground: ValueAnimator? = null
    private var animImageTransform: ValueAnimator? = null
    private var isInTransformAnimation = false
    private val mGestureDetector: GestureDetector
    private var isInitLayout = false
    protected var initI // 显示ImageWatcher时点击view
            : ImageView? = null
    protected var initImageGroupList // imageView控件映射列表
            : SparseArray<ImageView>? = null
    protected var initUrlList: List<Uri?>? = null
    private var pictureLongPressListener // 图片长按回调
            : OnPictureLongPressListener? = null
    private var adapter: ImagePagerAdapter? = null
    private var vPager: ViewPager? = null
    protected var mImageGroupList // 图片所在的ImageView控件集合，Int类型的Key对应position
            : SparseArray<ImageView>? = null
    protected var mUrlList // 图片地址列表
            : List<Uri?>? = null
    protected var initPosition = 0
    var currentPosition = 0
        private set
    private var mPagerPositionOffsetPixels // viewpager当前在屏幕上偏移量
            = 0
    private var loader // 图片加载者
            : Loader? = null
    private var onDimissListener: OnDimissListener? = null
    private var stateChangedListener: OnStateChangedListener? = null
    private var indexProvider // 索引ui接口
            : IndexProvider? = null
    private var idxView // 索引ui
            : View? = null
    private var loadingUIProvider // 加载ui
            : LoadingUIProvider? = null
    private val btmViewProvider: BtmViewProvider?
    private val activity: Activity?
    private val fragment: Fragment?
    private var detachAffirmative // dismiss detach parent 退出查看大图模式后，立即释放内存
            = false
    private var detachedParent = false
    private var isEnterAnimation = true //进入动画

    @JvmOverloads
    constructor(
        context: Context?,
        btmViewProvider: BtmViewProvider? = null,
        activity: Activity? = null,
        fragment: Fragment? = null,
        isLoadingUIProvider: Boolean = true
    ) : this(context, null, btmViewProvider, activity, fragment, isLoadingUIProvider) {
    }

    fun setEnterAnimation(isEnterAnimation: Boolean) {
        this.isEnterAnimation = isEnterAnimation
    }

    fun setLoader(l: Loader?) {
        loader = l
    }

    fun setDetachAffirmative() {
        detachAffirmative = true
    }

    fun setIndexProvider(ip: IndexProvider?) {
        indexProvider = ip
        if (indexProvider != null) {
            if (idxView != null) removeView(idxView)
            idxView = indexProvider!!.initialView(context)
            addView(idxView)
        }
    }

    fun setLoadingUIProvider(lp: LoadingUIProvider?) {
        loadingUIProvider = lp
    }

    fun setOnDimissListener(onDimissListener: OnDimissListener?) {
        this.onDimissListener = onDimissListener
    }

    fun setOnStateChangedListener(changedListener: OnStateChangedListener?) {
        stateChangedListener = changedListener
    }

    fun setOnPictureLongPressListener(listener: OnPictureLongPressListener?) {
        pictureLongPressListener = listener
    }

    interface Loader {
        fun load(context: Context?, uri: Uri?, lc: LoadCallback?)
    }

    interface LoadCallback {
        fun onResourceReady(resource: Drawable, url: String?, isGif: Boolean)
        fun onLoadStarted(placeholder: Drawable?)
        fun onLoadFailed(errorDrawable: Drawable?)
    }

    interface BtmViewProvider {
        fun initialView(context: Context?, imageWatcher: ImageWatcher?, activity: Activity?, fragment: Fragment?): View?
    }

    interface IndexProvider {
        fun initialView(context: Context): View?
        fun onPageChanged(imageWatcher: ImageWatcher?, position: Int, dataList: List<Uri?>?)
    }

    inner class DefaultIndexProvider : IndexProvider {
        var tCurrentIdx: TextView? = null
        override fun initialView(context: Context): View? {
            tCurrentIdx = TextView(context)
            val lpCurrentIdx = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
            lpCurrentIdx.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
            tCurrentIdx!!.layoutParams = lpCurrentIdx
            tCurrentIdx!!.setTextColor(-0x1)
            val displayMetrics = context.resources.displayMetrics
            val tCurrentIdxTransY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, -10f, displayMetrics) + 0.5f
            tCurrentIdx!!.translationY = tCurrentIdxTransY
            return tCurrentIdx
        }

        override fun onPageChanged(imageWatcher: ImageWatcher?, position: Int, dataList: List<Uri?>?) {
            if (mUrlList!!.size > 1) {
                tCurrentIdx!!.visibility = VISIBLE
                val idxInfo = (position + 1).toString() + " / " + mUrlList!!.size
                tCurrentIdx!!.text = idxInfo
            } else {
                tCurrentIdx!!.visibility = GONE
            }
        }
    }

    interface LoadingUIProvider {
        fun initialView(context: Context): View
        fun start(loadView: View)
        fun stop(loadView: View)
    }

    inner class ImageLoadingUIProvider : LoadingUIProvider {
        //        final LayoutParams lpCenterInParent = new LayoutParams(LayoutParams.MATCH_PARENT, ScreenUtils.getScreenHeight(getContext()) / 3);
        val lpCenterInParent = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        override fun initialView(context: Context): View {
            lpCenterInParent.gravity = Gravity.CENTER
            val imgv = ImageView(context)
            imgv.layoutParams = lpCenterInParent
            imgv.scaleType = ImageView.ScaleType.CENTER_CROP
            imgv.setImageDrawable(context.getDrawable(mPlaceholderRes))
            return imgv
        }

        override fun start(loadView: View) {
            loadView.visibility = VISIBLE
        }

        override fun stop(loadView: View) {
            loadView.visibility = GONE
        }
    }

    inner class DefaultLoadingUIProvider : LoadingUIProvider {
        val lpCenterInParent = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        override fun initialView(context: Context): View {
            lpCenterInParent.gravity = Gravity.CENTER
            val progressView = ProgressView(context)
            progressView.layoutParams = lpCenterInParent
            return progressView
        }

        override fun start(loadView: View) {
            loadView.visibility = VISIBLE
            (loadView as ProgressView).start()
        }

        override fun stop(loadView: View) {
            (loadView as ProgressView).stop()
            loadView.setVisibility(GONE)
        }
    }

    private val isHasGif: Boolean
        private get() {
            if (null == initUrlList || initUrlList!!.isEmpty()) return false
            for (i in initUrlList!!.indices) {
                if (initUrlList!![i] != null && initUrlList!![i].toString().toLowerCase().contains(".gif")) return true
            }
            return false
        }

    open interface OnDimissListener {
        fun onDimiss(isHasGif: Boolean, initUrlList: List<Uri?>?, views: SparseArray<ImageView>?)
    }

    interface OnStateChangedListener {
        fun onStateChangeUpdate(imageWatcher: ImageWatcher?, clicked: ImageView?, position: Int, uri: Uri?, animatedValue: Float, actionTag: Int)
        fun onStateChanged(imageWatcher: ImageWatcher?, position: Int, uri: Uri?, actionTag: Int)
    }

    interface OnPictureLongPressListener {
        /**
         * @param v   当前被按的ImageView
         * @param uri 当前ImageView加载展示的图片地址
         * @param pos 当前ImageView在展示组中的位置
         */
        fun onPictureLongPress(v: ImageView?, uri: Uri?, pos: Int) // 当前展示图片长按的回调
    }

    fun show(urlList: List<Uri?>?, initPos: Int) {
        if (urlList == null) {
            throw NullPointerException("urlList[null]")
        }
        if (initPos >= urlList.size || initPos < 0) {
            throw IndexOutOfBoundsException("initPos[" + initPos + "]  urlList.size[" + urlList.size + "]")
        }
        initPosition = initPos
        showInternal(null, null, urlList)
    }

    /**
     * 调用show方法前，请先调用setLoader 给ImageWatcher提供加载图片的实现
     *
     * @param i              被点击的ImageView
     * @param imageGroupList 被点击的ImageView的所在列表，加载图片时会提前展示列表中已经下载完成的thumb图片
     * @param urlList        被加载的图片url列表，数量必须大于等于 imageGroupList.size。 且顺序应当和imageGroupList保持一致
     */
    fun show(i: ImageView?, imageGroupList: SparseArray<ImageView>?, urlList: List<Uri?>?) {
        if (i == null || imageGroupList == null || urlList == null) {
            throw NullPointerException("i[$i]  imageGroupList[$imageGroupList]  urlList[$urlList]")
        }
        initPosition = -1
        for (x in 0 until imageGroupList.size()) {
            if (imageGroupList[imageGroupList.keyAt(x)] === i) {
                initPosition = imageGroupList.keyAt(x)
                break
            }
        }
        require(initPosition >= 0) { "param ImageView i must be a member of the List <ImageView> imageGroupList!" }
        showInternal(i, imageGroupList, urlList)
    }

    private fun showInternal(i: ImageView?, imageGroupList: SparseArray<ImageView>?, urlList: List<Uri?>) {
        if (loader == null) {
            throw NullPointerException("please invoke `setLoader` first [loader == null]")
        }
        if (i != null && i.drawable == null) return
        if (!isInitLayout) {
            initI = i
            initImageGroupList = imageGroupList
            initUrlList = urlList
            return
        }
        currentPosition = initPosition
        if (animImageTransform != null) animImageTransform!!.cancel()
        animImageTransform = null
        mImageGroupList = imageGroupList
        mUrlList = urlList
        iSource = null
        this@ImageWatcher.visibility = VISIBLE
        setEnterAnimation(i != null)
        vPager!!.adapter = ImagePagerAdapter().also { adapter = it }
        vPager!!.currentItem = initPosition
        if (indexProvider != null) indexProvider!!.onPageChanged(this, initPosition, mUrlList)
    }

    val currentUri: Uri?
        get() = if (mUrlList == null || mUrlList!!.isEmpty()) null else mUrlList!![currentPosition]
    val displayingUri: Uri?
        get() = if (mUrlList != null) mUrlList!![currentPosition] else null
    private var btmView: View? = null
    private fun setBtmFrameLayout() {
        if (null == btmViewProvider) return
        if (btmView != null) {
            removeView(btmView)
        }
        btmView = btmViewProvider.initialView(context, this, activity, fragment)
        val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
        lp.gravity = Gravity.BOTTOM or Gravity.RIGHT
        addView(btmView, lp)

//        DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
//        float tCurrentIdxTransY = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, -45, displayMetrics) + 0.5f;
//        btmView.setTranslationY(tCurrentIdxTransY);
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        return if (btmView != null && isTouchPointInView(btmView, ev)) {
            false
        } else mPagerPositionOffsetPixels == 0
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (iSource == null) return true
        if (isInTransformAnimation) return true
        if (animFling != null) {
            animFling!!.cancel()
            animFling = null
            mTouchMode = TOUCH_MODE_DOWN
        }
        val action = event.action and MotionEvent.ACTION_MASK
        when (action) {
            MotionEvent.ACTION_UP -> onUp(event)
            MotionEvent.ACTION_POINTER_DOWN -> if (mPagerPositionOffsetPixels == 0) { // 正在查看一张图片，不处于翻页中。
                if (mTouchMode != TOUCH_MODE_SCALE) {
                    mFingersDistance = 0f
                    mFingersCenterX = 0f
                    mFingersCenterY = 0f
                    ViewState.write(iSource, ViewState.STATE_TOUCH_SCALE)
                }
                mTouchMode = TOUCH_MODE_SCALE // 变化为缩放状态
            } else {
                dispatchEventToViewPager(event)
            }
            MotionEvent.ACTION_POINTER_UP -> if (mPagerPositionOffsetPixels == 0) { // 正在查看一张图片，不处于翻页中。
                if (event.pointerCount - 1 < 1 + 1) {
                    mTouchMode = TOUCH_MODE_SCALE_LOCK
                    onUp(event) // 结束缩放状态
                }
            } else {
                dispatchEventToViewPager(event)
            }
        }
        return mGestureDetector.onTouchEvent(event)
    }

    override fun onDown(e: MotionEvent): Boolean {
        mTouchMode = TOUCH_MODE_DOWN
        dispatchEventToViewPager(e)
        return true
    }

    private fun onUp(e: MotionEvent?) {
        // mTouchMode == TOUCH_MODE_AUTO_FLING -> nothing
        if (mTouchMode == TOUCH_MODE_SCALE || mTouchMode == TOUCH_MODE_SCALE_LOCK) {
            handleScaleTouchResult()
        } else if (mTouchMode == TOUCH_MODE_EXIT) {
            handleExitTouchResult()
        } else if (mTouchMode == TOUCH_MODE_DRAG) {
            handleDragTouchResult()
        } else if (mTouchMode == TOUCH_MODE_SLIDE) {
            dispatchEventToViewPager(e)
        }
    }

    private fun dispatchEventToViewPager(e2: MotionEvent?, e1: MotionEvent? = null) {
        try {
            if (e2 != null) {
                val moveX: Float = if (e1 != null) e2.x - e1.x else 0f
                val moveY: Float = if (e1 != null) e2.y - e1.y else 0f
                if (Math.abs(moveY) > mTouchSlop * 3 && Math.abs(moveX) < mTouchSlop && mPagerPositionOffsetPixels == 0) {
                    ViewState.write(iSource, ViewState.STATE_EXIT)
                    mTouchMode = TOUCH_MODE_EXIT // 下拉返回不灵 mTouchMode SLIDE 变化为 EXIT
                }
            }
            vPager!!.onTouchEvent(e2)
        } catch (ignore: Exception) {
        }
    }

    //(x,y)是否在view的区域内
    private fun isTouchPointInView(view: View?, e: MotionEvent): Boolean {
        if (view == null) {
            return false
        }
        val x = e.rawX.toInt()
        val y = e.rawY.toInt()
        val location = IntArray(2)
        view.getLocationOnScreen(location)
        val left = location[0]
        val top = location[1]
        val right = left + view.measuredWidth
        val bottom = top + view.measuredHeight
        //view.isClickable() &&
        return if (y >= top && y <= bottom && x >= left && x <= right
        ) {
            true
        } else false
    }

    override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
        if (mTouchMode == TOUCH_MODE_DOWN) {
            val moveX: Float = if (e1 != null) e2.x - e1.x else 0f
            val moveY: Float = if (e1 != null) e2.y - e1.y else 0f
            if (Math.abs(moveX) > mTouchSlop || Math.abs(moveY) > mTouchSlop) {
                val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
                val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT)
                val imageOrientation = iSource!!.getTag(R.id.image_orientation) as String
                if (vsDefault == null) {
                    // 没有vsDefault标志的View说明图标正在下载中。转化为Slide手势，可以进行viewpager的翻页滑动
                    mTouchMode = TOUCH_MODE_SLIDE
                } else if (Math.abs(moveX) < mTouchSlop && moveY > Math.abs(moveX) * 3 && vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2 <= iSource!!.translationY) {
                    // 手指垂直下拉。 横图未放大or图片放大且显示出了顶端   转化为退出查看图片操作
                    if (mTouchMode != TOUCH_MODE_EXIT) {
                        ViewState.write(iSource, ViewState.STATE_EXIT)
                    }
                    mTouchMode = TOUCH_MODE_EXIT
                } else if (vsCurrent.scaleY > vsDefault.scaleY || vsCurrent.scaleX > vsDefault.scaleX || vsCurrent.scaleY * iSource!!.height > mHeight) {
                    // 图片当前为放大状态(宽或高超出了屏幕尺寸)or竖图
                    if (mTouchMode != TOUCH_MODE_DRAG) {
                        ViewState.write(iSource, ViewState.STATE_DRAG)
                    }
                    mTouchMode = TOUCH_MODE_DRAG // 转化为Drag手势，可以对图片进行拖拽操作
                    if ("horizontal" == imageOrientation) {
                        // 图片位于边界，且仍然尝试向边界外拽动。。转化为Slide手势，可以进行viewpager的翻页滑动
                        val translateXEdge = vsDefault.width * (vsCurrent.scaleX - 1) / 2
                        if (vsCurrent.translationX >= translateXEdge && moveX > 0) {
                            mTouchMode = TOUCH_MODE_SLIDE
                        } else if (vsCurrent.translationX <= -translateXEdge && moveX < 0) {
                            mTouchMode = TOUCH_MODE_SLIDE
                        }
                    } else if ("vertical" == imageOrientation) {
                        if (vsDefault.width * vsCurrent.scaleX <= mWidth) {
                            if (Math.abs(moveY) < mTouchSlop && Math.abs(moveX) > mTouchSlop && Math.abs(moveX) > Math.abs(moveY) * 2) {
                                mTouchMode = TOUCH_MODE_SLIDE
                            }
                        } else {
                            val translateXRightEdge = vsDefault.width * vsCurrent.scaleX / 2 - vsDefault.width / 2
                            val translateXLeftEdge = mWidth - vsDefault.width * vsCurrent.scaleX / 2 - vsDefault.width / 2
                            if (vsCurrent.translationX >= translateXRightEdge && moveX > 0) {
                                mTouchMode = TOUCH_MODE_SLIDE
                            } else if (vsCurrent.translationX <= translateXLeftEdge && moveX < 0) {
                                mTouchMode = TOUCH_MODE_SLIDE
                            }
                        }
                    }
                } else if (Math.abs(moveX) > mTouchSlop) {
                    mTouchMode = TOUCH_MODE_SLIDE // 左右滑动。转化为Slide手势，可以进行viewpager的翻页滑动
                }
            }
        }
        if (mTouchMode == TOUCH_MODE_SLIDE) {
            dispatchEventToViewPager(e2, e1)
        } else if (mTouchMode == TOUCH_MODE_SCALE) {
            handleScaleGesture(e2)
        } else if (mTouchMode == TOUCH_MODE_EXIT) {
            handleExitGesture(e2, e1)
        } else if (mTouchMode == TOUCH_MODE_DRAG) {
            handleDragGesture(e2, e1)
        }
        return false
    }

    /**
     * 处理单击的手指事件
     */
    fun onSingleTapConfirmed(): Boolean {
        if (iSource == null) return false
        val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT)
        mExitRef = if (vsDefault == null || vsCurrent.scaleY <= vsDefault.scaleY && vsCurrent.scaleX <= vsDefault.scaleX) {
            0f
        } else {
            iSource!!.setTag(ViewState.STATE_EXIT, vsDefault)
            1f
        }
        handleExitTouchResult()
        return true
    }

    override fun onSingleTapUp(e: MotionEvent): Boolean {
        val hadTapMessage = mHandler.hasMessages(SINGLE_TAP_UP_CONFIRMED)
        if (hadTapMessage) {
            mHandler.removeMessages(SINGLE_TAP_UP_CONFIRMED)
            handleDoubleTapTouchResult()
            return true
        } else {
            mHandler.sendEmptyMessageDelayed(SINGLE_TAP_UP_CONFIRMED, 350)
        }
        return false
    }

    override fun onShowPress(e: MotionEvent) {}
    override fun onLongPress(e: MotionEvent) {
        if (pictureLongPressListener != null) {
            pictureLongPressListener!!.onPictureLongPress(iSource, mUrlList!![vPager!!.currentItem], vPager!!.currentItem)
        }
    }

    override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
        if (iSource != null && mTouchMode != TOUCH_MODE_AUTO_FLING && mPagerPositionOffsetPixels == 0) {
            val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
            val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT) ?: return false
            val imageOrientation = iSource!!.getTag(R.id.image_orientation) as String
            if (velocityX > 0 && vsCurrent.translationX == vsDefault.width * (vsCurrent.scaleX - 1) / 2 && "horizontal" == imageOrientation) {
                return false // 当前图片[横图]左侧边缘手指右划
            } else if (velocityX < 0 && -vsCurrent.translationX == vsDefault.width * (vsCurrent.scaleX - 1) / 2 && "horizontal" == imageOrientation) {
                return false // 当前图片[横图]右侧边缘手指左划
            } else if (e1 != null && e2 != null && (Math.abs(e1.x - e2.x) > 50 || Math.abs(e1.y - e2.y) > 50) && (Math.abs(velocityX) > 500 || Math.abs(
                    velocityY
                ) > 500)
            ) {
                // 满足fling手势
                var maxVelocity = Math.max(Math.abs(velocityX), Math.abs(velocityY))
                var endTranslateX = vsCurrent.translationX + velocityX * 0.2f
                var endTranslateY = vsCurrent.translationY + velocityY * 0.2f
                if (vsCurrent.scaleY * iSource!!.height < mHeight) {
                    endTranslateY = vsCurrent.translationY // 当前状态下判定为 横图(所显示高度不过全屏)
                    maxVelocity = Math.abs(velocityX)
                }
                if (vsCurrent.scaleY * iSource!!.height > mHeight && vsCurrent.scaleX == vsDefault.scaleX) {
                    endTranslateX = vsCurrent.translationX // 当前状态下判定为 竖图(所显示宽度不过全屏)
                    maxVelocity = Math.abs(velocityY)
                }
                val overflowX = mWidth * 0.02f
                val translateXEdge = vsDefault.width * (vsCurrent.scaleX - 1) / 2
                if (endTranslateX > translateXEdge + overflowX) endTranslateX =
                    translateXEdge + overflowX else if (endTranslateX < -translateXEdge - overflowX) endTranslateX = -translateXEdge - overflowX
                if (vsCurrent.scaleY * iSource!!.height > mHeight) {
                    val overflowY = mHeight * 0.02f
                    val translateYTopEdge = vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
                    val translateYBottomEdge = mHeight - vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
                    if (endTranslateY > translateYTopEdge + overflowY) {
                        endTranslateY = translateYTopEdge + overflowY
                    } else if (endTranslateY < translateYBottomEdge - overflowY) {
                        endTranslateY = translateYBottomEdge - overflowY
                    }
                }
                animFling(
                    iSource!!,
                    ViewState.write(iSource, ViewState.STATE_TEMP).translationX(endTranslateX).translationY(endTranslateY),
                    (1000000 / maxVelocity).toLong()
                )
                return true
            }
        }
        return false
    }

    /**
     * 处理响应退出图片查看
     */
    private fun handleExitGesture(e2: MotionEvent, e1: MotionEvent?) {
        if (iSource == null) return
        val vsExit = ViewState.read(iSource, ViewState.STATE_EXIT)
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT)
        if (vsExit == null || vsDefault == null) return
        mExitRef = 1f
        val moveY = e2.y - (e1?.y ?: 0f)
        val moveX = e2.x - (e1?.x ?: 0f)
        if (moveY > 0) mExitRef -= moveY / (mHeight / 2)
        if (mExitRef < 0) mExitRef = 0f
        setBackgroundColor(mColorEvaluator.evaluate(mExitRef, 0x00000000, -0x1000000))
        val exitScale = MIN_SCALE + (vsExit.scaleX - MIN_SCALE) * mExitRef
        iSource!!.scaleX = exitScale
        iSource!!.scaleY = exitScale
        val exitTrans = vsDefault.translationX + (vsExit.translationX - vsDefault.translationX) * mExitRef
        iSource!!.translationX = exitTrans + moveX
        iSource!!.translationY = vsExit.translationY + moveY
        //        if(onDimissListener != null)
//            onDimissListener.onDimiss();
    }

    /**
     * 处理响应单手拖拽平移
     */
    private fun handleDragGesture(e2: MotionEvent, e1: MotionEvent?) {
        if (iSource == null) return
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT)
        val vsTouchDrag = ViewState.read(iSource, ViewState.STATE_DRAG)
        if (vsDefault == null || vsTouchDrag == null) return
        val moveY = e2.y - (e1?.y ?: 0f)
        val moveX = e2.x - (e1?.x ?: 0f)
        var translateXValue = vsTouchDrag.translationX + moveX
        var translateYValue = vsTouchDrag.translationY + moveY
        val imageOrientation = iSource!!.getTag(R.id.image_orientation) as String
        if ("horizontal" == imageOrientation) {
            val translateXEdge = vsDefault.width * (vsTouchDrag.scaleX - 1) / 2
            if (translateXValue > translateXEdge) {
                translateXValue = translateXEdge + (translateXValue - translateXEdge) * edgeResilience
            } else if (translateXValue < -translateXEdge) {
                translateXValue = -translateXEdge + (translateXValue - -translateXEdge) * edgeResilience
            }
            iSource!!.translationX = translateXValue
        } else if ("vertical" == imageOrientation) {
            if (vsDefault.width * vsTouchDrag.scaleX <= mWidth) {
                translateXValue = vsTouchDrag.translationX
            } else {
                val translateXRightEdge = vsDefault.width * vsTouchDrag.scaleX / 2 - vsDefault.width / 2
                val translateXLeftEdge = mWidth - vsDefault.width * vsTouchDrag.scaleX / 2 - vsDefault.width / 2
                if (translateXValue > translateXRightEdge) {
                    translateXValue = translateXRightEdge + (translateXValue - translateXRightEdge) * edgeResilience
                } else if (translateXValue < translateXLeftEdge) {
                    translateXValue = translateXLeftEdge + (translateXValue - translateXLeftEdge) * edgeResilience
                }
            }
            iSource!!.translationX = translateXValue
        }
        if (vsDefault.height * vsTouchDrag.scaleY > mHeight) {
            val translateYTopEdge = vsDefault.height * vsTouchDrag.scaleY / 2 - vsDefault.height / 2
            val translateYBottomEdge = mHeight - vsDefault.height * vsTouchDrag.scaleY / 2 - vsDefault.height / 2
            if (translateYValue > translateYTopEdge) {
                translateYValue = translateYTopEdge + (translateYValue - translateYTopEdge) * edgeResilience
            } else if (translateYValue < translateYBottomEdge) {
                translateYValue = translateYBottomEdge + (translateYValue - translateYBottomEdge) * edgeResilience
            }
            iSource!!.translationY = translateYValue
        }
    }

    /**
     * 处理响应双手拖拽缩放
     */
    private fun handleScaleGesture(e2: MotionEvent) {
        if (iSource == null) return
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT)
        val vsTouchScale = ViewState.read(iSource, ViewState.STATE_TOUCH_SCALE)
        if (vsDefault == null || vsTouchScale == null) return
        if (e2.pointerCount < 2) return
        val deltaX = e2.getX(1) - e2.getX(0)
        val deltaY = e2.getY(1) - e2.getY(0)
        val distance = Math.sqrt((deltaX * deltaX + deltaY * deltaY).toDouble()).toFloat()
        if (mFingersDistance == 0f) mFingersDistance = distance
        val changedScale = (mFingersDistance - distance) / (mWidth * scaleSensitivity)
        var scaleResultX = vsTouchScale.scaleX - changedScale
        if (scaleResultX < MIN_SCALE) scaleResultX = MIN_SCALE else if (scaleResultX > MAX_SCALE) scaleResultX = MAX_SCALE
        iSource!!.scaleX = scaleResultX
        var scaleResultY = vsTouchScale.scaleY - changedScale
        if (scaleResultY < MIN_SCALE) scaleResultY = MIN_SCALE else if (scaleResultY > MAX_SCALE) scaleResultY = MAX_SCALE
        iSource!!.scaleY = scaleResultY
        val centerX = (e2.getX(1) + e2.getX(0)) / 2
        val centerY = (e2.getY(1) + e2.getY(0)) / 2
        if (mFingersCenterX == 0f && mFingersCenterY == 0f) {
            mFingersCenterX = centerX
            mFingersCenterY = centerY
        }
        val changedCenterX = mFingersCenterX - centerX
        val changedCenterXValue = vsTouchScale.translationX - changedCenterX
        val fitTransX = 0f // to do 缩放中心修正~
        iSource!!.translationX = changedCenterXValue + fitTransX
        val changedCenterY = mFingersCenterY - centerY
        val changedCenterYValue = vsTouchScale.translationY - changedCenterY
        iSource!!.translationY = changedCenterYValue
    }

    /**
     * 处理结束双击的手指事件，进行图片放大到指定大小或者恢复到初始大小的收尾动画
     */
    private fun handleDoubleTapTouchResult() {
        if (iSource == null) return
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT) ?: return
        val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
        if (vsCurrent.scaleY <= vsDefault.scaleY && vsCurrent.scaleX <= vsDefault.scaleX) {
            var expectedScale = (MAX_SCALE - vsDefault.scaleX) * 0.4f + vsDefault.scaleX

            // 横向超长图片双击无法看清楚的问题
            val imageOrientation = iSource!!.getTag(R.id.image_orientation) as String
            if (imageOrientation == "horizontal") {
                val viewState = ViewState.read(iSource, ViewState.STATE_DEFAULT)
                //图片在双击的时候放大的倍数，如果图片过长看不放大根本看不见 #45 hu670014125
                val scale = (viewState.width / viewState.height).toFloat()
                var maxScale = MAX_SCALE
                if (scale > 2.0f) {
                    maxScale = MAX_SCALE * scale / 2
                }
                expectedScale = (maxScale - vsDefault.scaleX) * 0.4f + vsDefault.scaleX
            }
            animSourceViewStateTransform(
                iSource,
                ViewState.write(iSource, ViewState.STATE_TEMP).scaleX(expectedScale).scaleY(expectedScale)
            )
        } else {
            animSourceViewStateTransform(iSource, vsDefault)
        }
    }

    /**
     * 处理结束缩放旋转模式的手指事件，进行恢复到零旋转角度和大小收缩到正常范围以内的收尾动画<br></br>
     */
    private fun handleScaleTouchResult() {
        if (iSource == null) return
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT) ?: return
        val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
        val endScaleX: Float
        val endScaleY: Float
        endScaleX = if (vsCurrent.scaleX < vsDefault.scaleX) vsDefault.scaleX else vsCurrent.scaleX
        endScaleY = if (vsCurrent.scaleY < vsDefault.scaleY) vsDefault.scaleY else vsCurrent.scaleY
        val vsTemp = ViewState.copy(vsDefault, ViewState.STATE_TEMP).scaleX(endScaleX).scaleY(endScaleY)
        if (iSource!!.width * vsCurrent.scaleX > mWidth) {
            val endTranslateX: Float
            val translateXEdge = vsCurrent.width * (vsCurrent.scaleX - 1) / 2
            endTranslateX =
                if (vsCurrent.translationX > translateXEdge) translateXEdge else if (vsCurrent.translationX < -translateXEdge) -translateXEdge else vsCurrent.translationX
            vsTemp.translationX(endTranslateX) // 缩放结果X轴比屏幕宽度长
        }
        if (iSource!!.height * vsCurrent.scaleY > mHeight) {
            val endTranslateY: Float
            val translateYBottomEdge = vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
            val translateYTopEdge = mHeight - vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
            endTranslateY =
                if (vsCurrent.translationY > translateYBottomEdge) translateYBottomEdge else if (vsCurrent.translationY < translateYTopEdge) translateYTopEdge else vsCurrent.translationY
            vsTemp.translationY(endTranslateY)
        }
        iSource!!.setTag(ViewState.STATE_TEMP, vsTemp)
        animSourceViewStateTransform(iSource, vsTemp)
        animBackgroundTransform(-0x1000000, 0)
    }

    /**
     * 处理结束拖拽模式的手指事件，进行超过边界则恢复到边界的收尾动画
     */
    private fun handleDragTouchResult() {
        if (iSource == null) return
        val vsDefault = ViewState.read(iSource, ViewState.STATE_DEFAULT) ?: return
        val vsCurrent = ViewState.write(iSource, ViewState.STATE_CURRENT)
        val endTranslateX: Float
        val endTranslateY: Float
        val imageOrientation = iSource!!.getTag(R.id.image_orientation) as String
        if ("horizontal" == imageOrientation) {
            val translateXEdge = vsDefault.width * (vsCurrent.scaleX - 1) / 2
            endTranslateX =
                if (vsCurrent.translationX > translateXEdge) translateXEdge else if (vsCurrent.translationX < -translateXEdge) -translateXEdge else vsCurrent.translationX
            endTranslateY = if (vsDefault.height * vsCurrent.scaleY <= mHeight) {
                vsDefault.translationY
            } else {
                val translateYBottomEdge = vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
                val translateYTopEdge = mHeight - vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
                if (vsCurrent.translationY > translateYBottomEdge) translateYBottomEdge else if (vsCurrent.translationY < translateYTopEdge) translateYTopEdge else vsCurrent.translationY
            }
        } else if ("vertical" == imageOrientation) {
            endTranslateX = if (vsDefault.width * vsCurrent.scaleX <= mWidth) {
                vsDefault.translationX
            } else {
                val translateXRightEdge = vsDefault.width * vsCurrent.scaleX / 2 - vsDefault.width / 2
                val translateXLeftEdge = mWidth - vsDefault.width * vsCurrent.scaleX / 2 - vsDefault.width / 2
                if (vsCurrent.translationX > translateXRightEdge) translateXRightEdge else if (vsCurrent.translationX < translateXLeftEdge) translateXLeftEdge else vsCurrent.translationX
            }
            val translateYBottomEdge = vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
            val translateYTopEdge = mHeight - vsDefault.height * vsCurrent.scaleY / 2 - vsDefault.height / 2
            endTranslateY =
                if (vsCurrent.translationY > translateYBottomEdge) translateYBottomEdge else if (vsCurrent.translationY < translateYTopEdge) translateYTopEdge else vsCurrent.translationY
        } else {
            return
        }
        if (vsCurrent.translationX == endTranslateX && vsCurrent.translationY == endTranslateY) {
            return  // 如果没有变化跳过动画实行时间的触摸锁定
        }
        animSourceViewStateTransform(
            iSource,
            ViewState.write(iSource, ViewState.STATE_TEMP).translationX(endTranslateX).translationY(endTranslateY)
        )
        animBackgroundTransform(-0x1000000, 0)
    }

    /**
     * 处理结束下拉退出的手指事件，进行退出图片查看或者恢复到初始状态的收尾动画<br></br>
     * 还需要还原背景色
     */
    private fun handleExitTouchResult() {
        if (iSource == null) return
        if (mExitRef > 0.75f) {
            val vsExit = ViewState.read(iSource, ViewState.STATE_EXIT)
            vsExit?.let { animSourceViewStateTransform(iSource, it) }
            animBackgroundTransform(-0x1000000, 0)
        } else {
            val vsOrigin = ViewState.read(iSource, ViewState.STATE_ORIGIN)
            if (vsOrigin != null) {
                if (vsOrigin.alpha == 0f) {
                    vsOrigin.translationX(iSource!!.translationX).translationY(iSource!!.translationY)
                }
                animSourceViewStateTransform(iSource, vsOrigin)
            }
            animBackgroundTransform(0x00000000, STATE_EXIT_HIDING)
            (iSource!!.parent as FrameLayout).getChildAt(2).animate().alpha(0f).start()
        }
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
        mPagerPositionOffsetPixels = positionOffsetPixels
    }

    /**
     * 每当ViewPager滑动到新的一页后，此方法会被触发<br></br>
     * 此刻必不可少的需要同步更新顶部索引，还原前一项后一项的状态等
     */
    @RequiresApi(Build.VERSION_CODES.S)
    override fun onPageSelected(position: Int) {
        iSource = adapter!!.mImageSparseArray[position]
        currentPosition = position
        if (indexProvider != null) indexProvider!!.onPageChanged(this, position, mUrlList)
        val mLast = adapter!!.mImageSparseArray[position - 1]
        if (ViewState.read(mLast, ViewState.STATE_DEFAULT) != null) {
            ViewState.restoreByAnim(mLast, ViewState.STATE_DEFAULT).create().start()
        }
        val mNext = adapter!!.mImageSparseArray[position + 1]
        if (ViewState.read(mNext, ViewState.STATE_DEFAULT) != null) {
            ViewState.restoreByAnim(mNext, ViewState.STATE_DEFAULT).create().start()
        }
    }

    override fun onPageScrollStateChanged(state: Int) {}
    internal inner class ImagePagerAdapter : PagerAdapter() {
        val mImageSparseArray = SparseArray<ImageView>()
        private var hasPlayBeginAnimation = false
        override fun getCount(): Int {
            return if (mUrlList != null) mUrlList!!.size else 0
        }

        override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
            container.removeView(`object` as View)
            mImageSparseArray.remove(position)
        }

        @RequiresApi(Build.VERSION_CODES.S)
        override fun instantiateItem(container: ViewGroup, position: Int): Any {
            val itemView = FrameLayout(container.context)
            container.addView(itemView)
            val imageView = ImageView(container.context)
            imageView.scaleType = ImageView.ScaleType.CENTER_CROP
            itemView.addView(imageView)
            mImageSparseArray.put(position, imageView)
            var loadView: View? = null
            if (loadingUIProvider != null) loadView = loadingUIProvider!!.initialView(container.context)
            if (loadView == null) {
                loadView = View(container.context) // 占位;errorView = getChildAt(2)
            }
            itemView.addView(loadView)
            val errorView = ImageView(container.context)
            errorView.scaleType = ImageView.ScaleType.CENTER_INSIDE
            errorView.setImageResource(mErrorImageRes)
            itemView.addView(errorView)
            errorView.visibility = GONE
            if (setDefaultDisplayConfigs(imageView, position, hasPlayBeginAnimation)) {
                hasPlayBeginAnimation = true
            }
            return itemView
        }

        override fun isViewFromObject(view: View, `object`: Any): Boolean {
            return view === `object`
        }

        /**
         * 更新ViewPager中每项的当前状态，比如是否加载，比如是否加载失败
         *
         * @param position 当前项的位置
         * @param loading  是否显示加载中
         * @param error    是否显示加载失败
         */
        fun notifyItemChangedState(position: Int, loading: Boolean, error: Boolean) {
            val imageView = mImageSparseArray[position]
            if (imageView != null) {
                val itemView = imageView.parent as FrameLayout
                val loadView = itemView.getChildAt(1)
                if (loadingUIProvider != null) {
                    if (loading) loadingUIProvider!!.start(loadView) else loadingUIProvider!!.stop(loadView)
                }
                val errorView = itemView.getChildAt(2) as ImageView
                errorView.alpha = 1f
                errorView.visibility = if (error) VISIBLE else GONE
            }
        }

        // Drawable转换成Bitmap
        fun drawable2Bitmap(drawable: Drawable): Bitmap {
            val bitmap = Bitmap
                .createBitmap(
                    drawable.intrinsicWidth,
                    drawable.intrinsicHeight,
                    if (drawable.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565
                )
            val canvas = Canvas(bitmap)
            drawable.setBounds(
                0, 0, drawable.intrinsicWidth,
                drawable.intrinsicHeight
            )
            drawable.draw(canvas)
            return bitmap
        }

        @RequiresApi(Build.VERSION_CODES.S)
        private fun setDefaultDisplayConfigs(imageView: ImageView, pos: Int, hasPlayBeginAnimation: Boolean): Boolean {
            var isFindEnterImagePicture = false
            if (pos == initPosition && !hasPlayBeginAnimation) {
                isFindEnterImagePicture = true
                iSource = imageView
            }
            var originRef: ImageView? = null
            if (mImageGroupList != null) {
                originRef = mImageGroupList!![pos]
            }
            if (originRef != null) {
                val location = IntArray(2)
                originRef.getLocationOnScreen(location)
                imageView.translationX = location[0].toFloat()
                var locationYOfFullScreen = location[1]
                locationYOfFullScreen -= mStatusBarHeight
                imageView.translationY = locationYOfFullScreen.toFloat()
                imageView.layoutParams.width = originRef.width
                imageView.layoutParams.height = originRef.height
                ViewState.write(imageView, ViewState.STATE_ORIGIN).width(originRef.width).height(originRef.height)
                val bmpMirror = originRef.drawable
                if (bmpMirror != null) {
                    val bmpMirrorWidth = bmpMirror.bounds.width()
                    val bmpMirrorHeight = bmpMirror.bounds.height()
                    val vsThumb = ViewState.write(imageView, ViewState.STATE_THUMB).width(bmpMirrorWidth).height(bmpMirrorHeight)
                        .translationX(((mWidth - bmpMirrorWidth) / 2).toFloat()).translationY(((mHeight - bmpMirrorHeight) / 2).toFloat())
                    imageView.setImageDrawable(bmpMirror)
                    if (isFindEnterImagePicture) {
                        animSourceViewStateTransform(imageView, vsThumb)
                    } else {
                        ViewState.restore(imageView, vsThumb.mTag)
                    }
                }
            } else {
                imageView.layoutParams.width = 0
                imageView.layoutParams.height = 0
                ViewState.write(imageView, ViewState.STATE_ORIGIN).alpha(0f).width(0).height(0).scaleXBy(1.5f).scaleY(1.5f)
            }
            val isPlayEnterAnimation = isFindEnterImagePicture
            // loadHighDefinitionPicture
            ViewState.clear(imageView, ViewState.STATE_DEFAULT)
            loader!!.load(imageView.context, mUrlList!![pos], object : LoadCallback {
                override fun onResourceReady(resource: Drawable, url: String?, isGif: Boolean) {
                    val sourceDefaultWidth: Int
                    val sourceDefaultHeight: Int
                    val sourceDefaultTranslateX: Int
                    val sourceDefaultTranslateY: Int
                    val resourceImageWidth = resource.intrinsicWidth
                    val resourceImageHeight = resource.intrinsicHeight
                    if (resourceImageWidth * 1f / resourceImageHeight > mWidth * 1f / mHeight) {
                        sourceDefaultWidth = mWidth
                        sourceDefaultHeight = (sourceDefaultWidth * 1f / resourceImageWidth * resourceImageHeight).toInt()
                        sourceDefaultTranslateX = 0
                        sourceDefaultTranslateY = (mHeight - sourceDefaultHeight) / 2
                        imageView.setTag(R.id.image_orientation, "horizontal")
                    } else {
                        sourceDefaultWidth = mWidth
                        sourceDefaultHeight = (sourceDefaultWidth * 1f / resourceImageWidth * resourceImageHeight).toInt()
                        sourceDefaultTranslateX = 0
                        sourceDefaultTranslateY = 0
                        imageView.setTag(R.id.image_orientation, "vertical")
                    }

//                    imageView.setImageDrawable(resource);
                    //避免图片太大OOM
                    if (isGif) {
                        imageView.setImageDrawable(resource)
                        //                        ImageManager.INSTANCE.loadGif(url, imageView);
                    } else {
                        imageView.setImageBitmap(drawable2Bitmap(resource))
                    }
                    notifyItemChangedState(pos, false, false)
                    val vsDefault = ViewState.write(imageView, ViewState.STATE_DEFAULT).width(sourceDefaultWidth).height(sourceDefaultHeight)
                        .translationX(sourceDefaultTranslateX.toFloat()).translationY(sourceDefaultTranslateY.toFloat())
                    if (!isEnterAnimation) {
                        ViewState.restore(imageView, vsDefault.mTag)
                    } else if (isPlayEnterAnimation) {
                        animSourceViewStateTransform(imageView, vsDefault)
                    } else {
                        ViewState.restore(imageView, vsDefault.mTag)
                        imageView.alpha = 0f
                        imageView.animate().alpha(1f).start()
                    }
                    imageView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
                        override fun onViewAttachedToWindow(v: View) {}
                        override fun onViewDetachedFromWindow(v: View) {
                            val displayingDrawable = imageView.drawable
                            if (displayingDrawable is Animatable) {
                                (displayingDrawable as Animatable).stop()
                            }
                        }
                    })
                    val displayingDrawable = imageView.drawable
                    if (displayingDrawable is Animatable) {
                        (displayingDrawable as Animatable).start()
                    }
                }

                override fun onLoadStarted(placeholder: Drawable?) {
                    notifyItemChangedState(pos, true, false)
                }

                override fun onLoadFailed(errorDrawable: Drawable?) {
                    notifyItemChangedState(pos, false, imageView.drawable == null)
                }
            })
            if (!isEnterAnimation) {
                setBackgroundColor(-0x1000000)
            } else if (isPlayEnterAnimation) {
                animBackgroundTransform(-0x1000000, STATE_ENTER_DISPLAYING)
            }
            return isPlayEnterAnimation
        }
    }

    private class RefHandler internal constructor(ref: ImageWatcher) : Handler() {
        var mRef: WeakReference<ImageWatcher>
        override fun handleMessage(msg: Message) {
            val holder = mRef.get()
            if (holder != null) {
                when (msg.what) {
                    SINGLE_TAP_UP_CONFIRMED -> holder.onSingleTapConfirmed()
                    DATA_INITIAL -> holder.internalDisplayDataAfterLayout()
                    else -> throw RuntimeException("Unknown message $msg") //never
                }
            }
        }

        init {
            mRef = WeakReference(ref)
        }
    }

    /**
     * 动画执行时加入这个监听器后会自动记录标记 [ImageWatcher.isInTransformAnimation] 的状态<br></br>
     * isInTransformAnimation值为true的时候可以达到在动画执行时屏蔽触摸操作的目的
     */
    private val mAnimTransitionStateListener: AnimatorListenerAdapter = object : AnimatorListenerAdapter() {
        override fun onAnimationCancel(animation: Animator) {
            isInTransformAnimation = false
        }

        override fun onAnimationStart(animation: Animator) {
            isInTransformAnimation = true
            mTouchMode = TOUCH_MODE_AUTO_FLING
        }

        override fun onAnimationEnd(animation: Animator) {
            isInTransformAnimation = false
        }
    }
    private val mColorEvaluator = TypeEvaluator<Int> { fraction, startValue, endValue ->
        val f = accelerateInterpolator.getInterpolation(fraction)
        val alpha = (Color.alpha(startValue) + f * (Color.alpha(endValue) - Color.alpha(startValue))).toInt()
        val red = (Color.red(startValue) + f * (Color.red(endValue) - Color.red(startValue))).toInt()
        val green = (Color.green(startValue) + f * (Color.green(endValue) - Color.green(startValue))).toInt()
        val blue = (Color.blue(startValue) + f * (Color.blue(endValue) - Color.blue(startValue))).toInt()
        Color.argb(alpha, red, green, blue)
    }
    private val decelerateInterpolator = DecelerateInterpolator()
    private val accelerateInterpolator = AccelerateInterpolator()
    fun setTranslucentStatus(statusBarHeight: Int) {
        mStatusBarHeight = statusBarHeight
    }

    fun setmPlaceholderRes(mPlaceholderRes: Int) {
        this.mPlaceholderRes = mPlaceholderRes
    }

    fun setErrorImageRes(resErrorImage: Int) {
        mErrorImageRes = resErrorImage
    }

    override fun setBackgroundColor(color: Int) {
        mBackgroundColor = color
        super.setBackgroundColor(color)
    }

    override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) {
        super.onSizeChanged(w, h, oldW, oldH)
        mWidth = w
        mHeight = h
        if (!isInitLayout) {
            isInitLayout = true
            mHandler.sendEmptyMessage(DATA_INITIAL)
        }
    }

    private fun internalDisplayDataAfterLayout() {
        if (initUrlList != null) {
            showInternal(initI, initImageGroupList, initUrlList!!)
        }
    }

    override fun onDetachedFromWindow() {
        if (onDimissListener != null) onDimissListener!!.onDimiss(isHasGif, initUrlList, initImageGroupList)
        super.onDetachedFromWindow()
        if (animImageTransform != null) animImageTransform!!.cancel()
        animImageTransform = null
        if (animBackground != null) animBackground!!.cancel()
        animBackground = null
        if (animFling != null) animFling!!.cancel()
        animFling = null
    }

    /**
     * 当界面处于图片查看状态需要在Activity中的[Activity.onBackPressed]
     * 将事件传递给ImageWatcher优先处理<br></br>
     * *ImageWatcher并没有从父View中移除
     * *当处于收尾动画执行状态时，消费返回键事件<br></br>
     * *当图片处于放大状态时，执行图片缩放到原始大小的动画，消费返回键事件<br></br>
     * *当图片处于原始状态时，退出图片查看，消费返回键事件<br></br>
     * *其他情况，ImageWatcher并没有展示图片
     */
    fun handleBackPressed(): Boolean {
        return !detachedParent && (isInTransformAnimation || iSource != null && visibility == VISIBLE && onSingleTapConfirmed())
    }

    /**
     * 将指定的ImageView形态(尺寸大小，缩放，旋转，平移，透明度)逐步转化到期望值
     */
    private fun animSourceViewStateTransform(view: ImageView?, vsResult: ViewState) {
        if (view == null) return
        if (animImageTransform != null) animImageTransform!!.cancel()
        animImageTransform = ViewState.restoreByAnim(view, vsResult.mTag).addListener(mAnimTransitionStateListener).create()
        if (animImageTransform != null) {
            if (vsResult.mTag == ViewState.STATE_ORIGIN) {
                animImageTransform!!.addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        // 如果是退出查看操作，动画执行完后，原始被点击的ImageView恢复可见
                        visibility = GONE
                    }
                })
            }
            animImageTransform!!.start()
        }
    }

    /**
     * 执行ImageWatcher自身的背景色渐变至期望值[colorResult]的动画
     */
    private fun animBackgroundTransform(colorResult: Int, tag: Int) {
        if (colorResult == mBackgroundColor) return
        if (animBackground != null) animBackground!!.cancel()
        val mCurrentBackgroundColor = mBackgroundColor
        animBackground = ValueAnimator.ofFloat(0f, 1f).setDuration(200)
        animBackground?.addUpdateListener(AnimatorUpdateListener { animation ->
            val p = animation.animatedValue as Float
            setBackgroundColor(mColorEvaluator.evaluate(p, mCurrentBackgroundColor, colorResult))
            if (stateChangedListener != null) {
                stateChangedListener!!.onStateChangeUpdate(this@ImageWatcher, iSource, currentPosition, displayingUri, p, tag)
            }
        })
        animBackground?.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
                super.onAnimationStart(animation)
                if (stateChangedListener != null) {
                    if (tag == STATE_ENTER_DISPLAYING) {
                        stateChangedListener!!.onStateChanged(this@ImageWatcher, currentPosition, displayingUri, tag)
                    }
                }
            }

            override fun onAnimationEnd(animation: Animator) {
                if (stateChangedListener != null) {
                    if (tag == STATE_EXIT_HIDING) {
                        stateChangedListener!!.onStateChanged(this@ImageWatcher, currentPosition, displayingUri, tag)
                    }
                }
                if (detachAffirmative && tag == STATE_EXIT_HIDING) {
                    detachedParent = true
                    if (parent != null) {
                        (parent as ViewGroup).removeView(this@ImageWatcher)
                    }
                }
            }
        })
        animBackground?.start()
    }

    private fun animFling(view: ImageView, vsResult: ViewState, duration: Long) {
        var duration = duration
        if (duration > 800) duration = 800 else if (duration < 100) duration = 100
        if (animFling != null) animFling!!.cancel()
        animFling = ViewState.restoreByAnim(view, vsResult.mTag).addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
                mTouchMode = TOUCH_MODE_AUTO_FLING
            }

            override fun onAnimationEnd(animation: Animator) {
                mTouchMode = TOUCH_MODE_SCALE_LOCK
                onUp(null)
            }
        }).create()
        animFling?.interpolator = decelerateInterpolator
        animFling?.duration = duration
        animFling?.start()
    }

    companion object {
        private const val SINGLE_TAP_UP_CONFIRMED = 1
        private const val DATA_INITIAL = 2
        const val STATE_ENTER_DISPLAYING = 3
        const val STATE_EXIT_HIDING = 4
        protected const val TOUCH_MODE_NONE = 0 // 无状态
        protected const val TOUCH_MODE_DOWN = 1 // 按下
        protected const val TOUCH_MODE_DRAG = 2 // 单点拖拽
        protected const val TOUCH_MODE_SLIDE = 4 // 页面滑动
        protected const val TOUCH_MODE_SCALE = 5 // 缩放
        protected const val TOUCH_MODE_SCALE_LOCK = 6 // 缩放锁定
        protected const val TOUCH_MODE_AUTO_FLING = 7 // 动画中
        protected const val TOUCH_MODE_EXIT = 3 // 退出动作
    }

    init {
        val nh = getNavigationBarHeightIfRoom(context)
        if (nh > 0) {
            val lp = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, getDpi(context!!) - nh
            )
            layoutParams = lp
        }
        mHandler = RefHandler(this)
        mGestureDetector = GestureDetector(context, this)
        context?.let {
            mTouchSlop = ViewConfiguration.get(it).scaledTouchSlop.toFloat()
        }
        addView(ViewPager(context!!).also { vPager = it })
        vPager!!.addOnPageChangeListener(this)
        visibility = INVISIBLE
        setIndexProvider(DefaultIndexProvider())
        //        setLoadingUIProvider(new DefaultLoadingUIProvider());
        if (isLoadingUIProvider) {
            setLoadingUIProvider(ImageLoadingUIProvider())
        }
        this.activity = activity
        this.fragment = fragment
        this.btmViewProvider = btmViewProvider
        setBtmFrameLayout()
    }
}